package com.ghh.test;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by zn on 2018/5/8.
 */
public class ISO8583Util {
    /**
     * 解析IC卡55域（银联、POS通用）
     *
     * @param f55
     * @return Map<tag, value></>
     * @throws Exception 关于55域
     *                   1、tag：1~2字节，左边第一字节的右5bit 为 11111，则tag占2字节，否则占1字节 （两字节一般格式 xFxx）
     *                   2、leng：1~3字节，左边字节最左bit为0，则剩下的7bit表示长度，范围 1~127
     *                   左边字节最左bit为1，则剩下的7bit表示长度的长度，如 10000001，表示后面还有1个字节的长度，范围 128~255
     *                   现在最多leng是3个字节，也就是左边字节只能是 0x80（右1字节长度）、0x81（右2字节长度）
     *                   3、value：
     */
    public static Map<String, String> decodeF55(byte[] f55) throws Exception {
        Map map = new HashMap<>();
        map.get("9F10");
        int offset = 0;
        while (offset < f55.length) {
            /* step 1: 取tag */
            int tagLength = (f55[offset] & 0x1F) == 0x1F ? 2 : 1; // 第1个字节后5bit全为1，则tag占2字节，否则占1字节
            byte[] tag = new byte[tagLength];
            System.arraycopy(f55, offset, tag, 0, tagLength);
            offset += tagLength;
            /* step 2: 取数据长度 */
            int valueLength = 0;
            if (f55[offset] >= 0) { // 判断最左bit为0时，长度占1个字节，后续7个bit表示长度， 1~127 (当最左bit为0时，比较时自动转换成int为非负数)
                valueLength = f55[offset++]; // 只用后7bit，不用处理符号位；支持长度为0的情况。
            } else if (f55[offset] == 0xffffff81) { // 1000 0001，后面1个字节表示长度，128~255
                valueLength = f55[offset + 1] & 0xFF; // 因为可以表示255，所以byte要转成无符号的
                offset += 2;
            } else if (f55[offset] == 0xffffff82) { // 1000 0010，后面2个字节表示长度
                valueLength = (f55[offset + 1] & 0xFF) << 8 | f55[offset + 2] & 0xFF; // 转成无符号
                offset += 3;
            } else { // 其他长度格式暂不支持
                throw new Exception("value length error!");
            }
            /* step 3: 取值 */
            byte[] value = null;
            if (0 != valueLength) {
                value = new byte[valueLength];
                System.arraycopy(f55, offset, value, 0, valueLength);
                offset += valueLength;
            }
            /* step 4: tag - value */
            map.put(hexBytesToStr(tag), hexBytesToStr(value));
        }
        return map;
    }

    /**
     * 十六进制的字符串 --> byte[] （"FF" --> 0xFF）
     *
     * @param str
     * @return
     */
    public static byte[] hexStrToBytes(String str) {
        if (null == str || str.trim().length() == 0) {
            return null;
        }
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }

    /**
     * byte[] --> 十六进制的字符串 (0xFF --> "FF")
     *
     * @param bytes
     * @return
     */
    public static String hexBytesToStr(byte[] bytes) {
        if (null == bytes) {
            return null;
        }
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            buf.append(String.format("%02X", new Integer(b & 0xff)));
        }
        return buf.toString();
    }

    public static void main(String[] args) throws Exception {
        StringBuilder sF55 = new StringBuilder();
        // 测试一下长度为0的情况
        sF55.append("9F00").append("00");
        // 测试一下长度为2字节的情况
        sF55.append("9F01").append("81fa").append("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
        // 测试一下长度为3字节的情况
        sF55.append("9F02").append("820100").append("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901");
        byte[] bF55 = hexStrToBytes("9F260879CC8EC5A09FB9479F2701809F100807010199A0B806019F3704000000009F360201C2950500001800009A031205089C01609F02060000000000005F2A02015682027D009F1A0201569F03060000000000009F3303E0F0F09F34036003029F3501119F1E0832303033313233318405FFFFFFFFFF9F090220069F4104000000019F74064543433030319F631030313032303030308030303030303030".toString());
        Map mapF55 = decodeF55(bF55);
        System.out.println(mapF55);
    }
}